package com.lx.wrapper.impl;


import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.lx.constant.ano.FieldFunction;
import com.lx.constant.consts.SqlFormatConstant;
import com.lx.constant.consts.SqlKeyWordConstant;
import com.lx.constant.enums.SegmentEnum;
import com.lx.constant.execption.LambdaCheckException;
import com.lx.constant.segment.Segment;
import com.lx.constant.segment.update.SetSegment;
import com.lx.wrapper.AbstractMainEntityLambdaConditionWrapper;
import com.lx.wrapper.AbstractWrapper;
import org.hibernate.query.Query;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

/**
 * Lambda更新语句对象
 *
 * @author lx
 * @create 2023/1/30 15:57
 **/
public class LambdaUpdateWrapper<MainEntity> extends AbstractMainEntityLambdaConditionWrapper<MainEntity, LambdaUpdateWrapper<MainEntity>> {

    public LambdaUpdateWrapper() {
        this(null);
    }

    public LambdaUpdateWrapper(Class<MainEntity> entityClass) {
        super(entityClass);
    }

    /**
     * 根据实体对象相关属性进行非空数据更新
     * 特殊场景：如本次更新时某些属性的Null值需要同步更新,请在可变参数处进行添加
     *
     * @param entityValue             待更新数据
     * @param needUpdateMayNullColumn 需要同步更新Null值列数组
     * @return
     */
    public LambdaUpdateWrapper<MainEntity> set(MainEntity entityValue, FieldFunction<MainEntity, ?>... needUpdateMayNullColumn) {
        throw new LambdaCheckException("暂未实现,请期待");
    }

    /**
     * 根据实体对象相关属性进行非空数据更新,当默认实体对象同待更新实体属性数据一致时,抛弃该属性数据的更新
     *
     * @param updateEntityValue 待更新实体
     * @param hedgingValue      对冲实体,如该实体同[待更新实体]属性的值一致,则不会更新
     * @return
     */
    public LambdaUpdateWrapper<MainEntity> set(MainEntity updateEntityValue, MainEntity hedgingValue) {
        throw new LambdaCheckException("暂未实现,请期待");
    }


    public LambdaUpdateWrapper<MainEntity> set(FieldFunction<MainEntity, ?> setColumnFieldFn, Object updateColVal) {
        return set(true, setColumnFieldFn, updateColVal);
    }

    public LambdaUpdateWrapper<MainEntity> set(String columnName, Object updateColVal) {
        return set(true, columnName, updateColVal);
    }

    public LambdaUpdateWrapper<MainEntity> set(FieldFunction<MainEntity, ?> setColumnFieldFn, AbstractMainEntityLambdaConditionWrapper updateChildWrapper) {
        return set(true, setColumnFieldFn, updateChildWrapper);
    }

    /**
     * 更新列对应的值
     *
     * @param condition        是否满足条件
     * @param setColumnFieldFn Lambda左列更新项
     * @param updateColVal     待更新列值
     * @return
     */
    public LambdaUpdateWrapper<MainEntity> set(boolean condition, FieldFunction<MainEntity, ?> setColumnFieldFn, Object updateColVal) {
        return condition ? addSetSegment(null, setColumnFieldFn, null, updateColVal) : this;
    }

    /**
     * 更新列对应的值
     *
     * @param condition    是否满足条件
     * @param columnName   左列更新列名
     * @param updateColVal 待更新列值
     * @return
     */
    public LambdaUpdateWrapper<MainEntity> set(boolean condition, String columnName, Object updateColVal) {
        return condition ? addSetSegment(columnName, null, null, updateColVal) : this;
    }

    /**
     * 提供更新值为子查询的方法
     * 注意:
     * 1.如存在子查询,则在HQL语法中使用Limit关键字时不会有效取出限制条数,这是由于HQL语句限制导致的;SQL语句仍旧支持子查询中携带Limit
     *
     * @param condition          是否满足条件
     * @param setColumnFieldFn   Lambda左列更新项
     * @param updateChildWrapper 待更新列子查询
     * @return
     */
    public LambdaUpdateWrapper<MainEntity> set(boolean condition, FieldFunction<MainEntity, ?> setColumnFieldFn, AbstractMainEntityLambdaConditionWrapper updateChildWrapper) {
        return condition ? addSetSegment(null, setColumnFieldFn, null, updateChildWrapper) : this;
    }

    public LambdaUpdateWrapper<MainEntity> setAdd(FieldFunction<MainEntity, ?> setColumnFieldFn, Object updateColVal) {
        return setAdd(true, setColumnFieldFn, updateColVal);
    }

    public LambdaUpdateWrapper<MainEntity> setAdd(FieldFunction<MainEntity, ?> setColumnFieldFn, FieldFunction<MainEntity, ?> updateColumnFieldFn, Object updateColVal) {
        return setAdd(true, setColumnFieldFn, updateColumnFieldFn, updateColVal);
    }

    /**
     * 提供列类型为数字且需要累加的数据更新,等同格式:
     * SET A列 = A列 + updateColVal
     *
     * @param condition
     * @param setColumnFieldFn
     * @param updateColVal
     * @return
     */
    public LambdaUpdateWrapper<MainEntity> setAdd(boolean condition, FieldFunction<MainEntity, ?> setColumnFieldFn, Object updateColVal) {
        return setAdd(condition, setColumnFieldFn, setColumnFieldFn, updateColVal);
    }

    /**
     * 提供列类型为数字且需要累加的数据更新,等同格式:
     * SET A列 = B列 + updateColVal
     *
     * @param condition
     * @param setColumnFieldFn
     * @param updateColVal
     * @return
     */
    public LambdaUpdateWrapper<MainEntity> setAdd(boolean condition, FieldFunction<MainEntity, ?> setColumnFieldFn, FieldFunction<MainEntity, ?> updateColumnFieldFn, Object updateColVal) {
        return condition ? addSetSegment(null, setColumnFieldFn, updateColumnFieldFn, updateColVal) : this;
    }

    @Override
    protected void setHibernateParamByQuery0(boolean isHQL, Query query) {
        //其他映射
        Map<SegmentEnum, List<Segment>> segmentsMap = getSegmentsByEnums(SegmentEnum.SET, SegmentEnum.WHERE, SegmentEnum.LIMIT);
        segmentsMap.forEach((e1, l1) -> {
            if (CollectionUtil.isEmpty(l1)) {
                return;
            }
            for (Segment sn : l1) {
                sn.setHibernateParamByQuery(isHQL, query);
            }
        });
    }

    @Override
    protected String getCompleteQL0(boolean isHQL, AbstractWrapper parentWrapper) {
        //根据条件构建更新SQL
        StringBuilder sqlBuilder = new StringBuilder(512);
        //1.组建 update 表名 语句
        sqlBuilder.append(SqlKeyWordConstant.UPDATE).append(String.format(SqlFormatConstant.AS_FORMAT, inferAndGetTableName(isHQL), getTableAliasName(false)));
        //2.构建SET语句
        sqlBuilder.append(buildConditions(isHQL, parentWrapper, SegmentEnum.SET));
        //3.构建条件项.
        sqlBuilder.append(buildConditions(isHQL, parentWrapper, SegmentEnum.WHERE));
        //4.构建分页条件
        sqlBuilder.append(buildConditions(isHQL, parentWrapper, SegmentEnum.LIMIT));
        return sqlBuilder.toString();
    }

    protected LambdaUpdateWrapper<MainEntity> addSetSegment(String columnName, FieldFunction<MainEntity, ?> setColumnFieldFn, FieldFunction<MainEntity, ?> updateColumnFieldFn, Object updateColValue) {
        return addSetSegment(columnName, setColumnFieldFn, updateColumnFieldFn, updateColValue, null);
    }

    /**
     * 添加更新列语句对象
     *
     * @param columnName          列名称
     * @param setColumnFieldFn    Lambda左列更新项
     * @param updateColumnFieldFn Lambda右列占位项
     * @param updateColValue      待更新值
     * @param updateChildWrapper  待更新列子查询
     * @return
     */
    protected LambdaUpdateWrapper<MainEntity> addSetSegment(String columnName, FieldFunction<MainEntity, ?> setColumnFieldFn, FieldFunction<MainEntity, ?> updateColumnFieldFn, Object updateColValue, AbstractMainEntityLambdaConditionWrapper updateChildWrapper) {
        Field setColumnField = getColumnFieldByFn(setColumnFieldFn);
        if (setColumnField == null && StrUtil.isEmpty(columnName)) {
            //Nothing: 如更新Lambda列或列名均未传入,意味着无法进行更新..
            return this;
        }

        SetSegment dc = createAndAddSegment(new SetSegment(), SegmentEnum.SET, setColumnField, columnName);

        dc.setColumnValue(updateColValue);
        dc.setChildConditionWrapper(updateChildWrapper);

        Field updateColumnField = getColumnFieldByFn(updateColumnFieldFn);
        if (updateColumnField != null) {
            Segment segment = new Segment();
            segment.setColumnField(updateColumnField);
            segment.setColumnFieldName(updateColumnField.getName());

            dc.setUpdateColumnSegment(segment);
        }
        return this;
    }
}
